package responseproxy

import (
	"context"
	"encoding/json"
	"fmt"
	"github.com/sirupsen/logrus"
	"gopkg.in/yaml.v2"
	"goproject/commonType"
	"goproject/logger"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/client-go/dynamic"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"
	"log"
	"math/rand"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"time"
)

func InitK8sClient() (dynamic.Interface, error) {
	// 使用 kubeconfig 配置
	var config *rest.Config
	var err error

	// 检查是否在集群内部运行
	if _, inCluster := os.LookupEnv("KUBERNETES_SERVICE_HOST"); inCluster {
		log.Println("在集群内部运行，使用 in-cluster 配置...")
		config, err = rest.InClusterConfig()
		if err != nil {
			log.Printf("获取 in-cluster 配置时出错: %v\n", err)
			return nil, err
		}
	} else {
		log.Println("在本地运行，使用 kubeconfig 文件...")

		// 使用当前用户主目录下的 kubeconfig 文件路径
		kubeconfig := filepath.Join(os.Getenv("HOME"), ".kube", "config")
		log.Printf("使用 kubeconfig 文件: %s\n", kubeconfig)

		config, err = clientcmd.BuildConfigFromFlags("", kubeconfig)
		if err != nil {
			log.Printf("从 kubeconfig 构建配置时出错: %v\n", err)
			return nil, err
		}
	}
	dynamicClient, err := dynamic.NewForConfig(config)
	if err != nil {
		return nil, fmt.Errorf("failed to create dynamic client: %v", err)
	}
	return dynamicClient, nil
}

const envoyFilterTemplate = `apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: ${envoyFiltername}
  namespace: ${namespace}
spec:
  workloadSelector:
    labels:
      name: ${servicename}
  configPatches:
    - applyTo: HTTP_FILTER
      match:
        context: SIDECAR_INBOUND
        listener:
          filterChain:
            filter:
              name: "envoy.filters.network.http_connection_manager"
              subFilter:
                name: "envoy.filters.http.router"
      patch:
        operation: INSERT_BEFORE
        value:
          name: envoy.filters.http.lua
          typed_config:
            "@type": type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua
            inlineCode: |
              function envoy_on_response(response_handle)
                response_handle:logInfo("Modified Response Body: ")
                -- 读取并修改响应体
                local body_size = response_handle:body():length()
                local body = response_handle:body():getBytes(0, body_size)
                local new_body = '${modifiedContent}'  -- 确保这是一个有效的JSON字符串
                response_handle:body():setBytes(new_body)
                 -- 日志输出修改后的内容
                response_handle:logInfo("Modified Response Body: " .. new_body)
              end
`

func ApplyEnvoyFilter(namespace, servicename string, modifiedContent commonType.StoredResponse) (string, error) {
	log := logrus.New()
	dynamicClient, err := InitK8sClient()
	if err != nil {
		log.Errorf("初始化 Kubernetes 客户端失败: %v", err)
		return "", err
	}

	modifiedContentJSON, err := json.Marshal(modifiedContent.Body)
	// 转义 JSON 内容以适应 YAML
	//modifiedContentEscaped := strings.ReplaceAll(string(modifiedContentJSON), `"`, `\"`)

	if err != nil {
		log.Errorf("序列化修改内容失败: %v", err)
		return "", err
	}

	// 生成 EnvoyFilter 名称
	filterName := generateValidName("filter-" + randomString(8))
	yamlContent := envoyFilterTemplate
	yamlContent = strings.ReplaceAll(yamlContent, "${envoyFiltername}", filterName)
	yamlContent = strings.ReplaceAll(yamlContent, "${namespace}", namespace)
	yamlContent = strings.ReplaceAll(yamlContent, "${servicename}", servicename)
	yamlContent = strings.ReplaceAll(yamlContent, "${modifiedContent}", string(modifiedContentJSON))
	log.Infof(yamlContent)

	var envoyFilter map[interface{}]interface{}
	err = yaml.Unmarshal([]byte(yamlContent), &envoyFilter)
	if err != nil {
		log.Errorf("反序列化 YAML 内容失败: %v", err)
		return "", err
	}

	// 转换 map[interface{}]interface{} 为 map[string]interface{}
	envoyFilterConverted := convertToMapStringInterface(envoyFilter)

	envoyFilterYAML, err := yaml.Marshal(envoyFilterConverted)
	if err != nil {
		log.Errorf("序列化 EnvoyFilter 为 YAML 失败: %v", err)
		return "", err
	}

	log.Infof("应用 EnvoyFilter:\n%s", string(envoyFilterYAML))

	// 使用 dynamic client 应用 EnvoyFilter
	gvr := schema.GroupVersionResource{
		Group:    "networking.istio.io",
		Version:  "v1alpha3",
		Resource: "envoyfilters",
	}
	_, err = dynamicClient.Resource(gvr).Namespace(namespace).Create(context.TODO(), &unstructured.Unstructured{Object: envoyFilterConverted}, metav1.CreateOptions{})
	if err != nil {
		log.Errorf("应用 EnvoyFilter 失败: %v", err)
		return "", err
	}
	log.Infof("EnvoyFilter %s 在命名空间 %s 中应用成功", filterName, namespace)
	return filterName, nil
}

// generateValidName 生成符合 Kubernetes 资源名称规范的名称
func generateValidName(name string) string {
	reg := regexp.MustCompile(`[^a-z0-9\-]+`)
	name = strings.ToLower(name)
	name = reg.ReplaceAllString(name, "-")
	name = strings.Trim(name, "-")
	if len(name) > 253 {
		name = name[:253]
	}
	return name
}
func DeleteEnvoyFilter(namespace, filterName string) error {
	log := logger.GetLogger()
	dynamicClient, err := InitK8sClient()
	if err != nil {
		log.Errorf("初始化 Kubernetes 客户端失败: %v", err)
		return err
	}

	gvr := schema.GroupVersionResource{
		Group:    "networking.istio.io",
		Version:  "v1alpha3",
		Resource: "envoyfilters",
	}

	err = dynamicClient.Resource(gvr).Namespace(namespace).Delete(context.TODO(), filterName, metav1.DeleteOptions{})
	if err != nil {
		log.Errorf("删除 EnvoyFilter %s 在命名空间 %s 中失败: %v", filterName, namespace, err)
		return err
	}
	log.Infof("EnvoyFilter %s 在命名空间 %s 中删除成功", filterName, namespace)
	return nil
}

func randomString(n int) string {
	rand.Seed(time.Now().UnixNano())
	letters := []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
	b := make([]rune, n)
	for i := range b {
		b[i] = letters[rand.Intn(len(letters))]
	}
	return string(b)
}

func replace(s, old, new string) string {
	return fmt.Sprintf(s, old, new)
}

// escapeJSONString 转义 JSON 字符串中的特殊字符
func escapeJSONString(str string) string {
	escapedStr := strings.ReplaceAll(str, `"`, `\"`)
	return escapedStr
}

// convertToMapStringInterface 将 map[interface{}]interface{} 转换为 map[string]interface{}
func convertToMapStringInterface(input map[interface{}]interface{}) map[string]interface{} {
	output := make(map[string]interface{})
	for key, value := range input {
		strKey := fmt.Sprintf("%v", key)
		switch value := value.(type) {
		case map[interface{}]interface{}:
			output[strKey] = convertToMapStringInterface(value)
		case []interface{}:
			output[strKey] = convertSlice(value)
		default:
			output[strKey] = value
		}
	}
	return output
}

// convertSlice 递归转换 slice 中的 map[interface{}]interface{} 类型
func convertSlice(input []interface{}) []interface{} {
	output := make([]interface{}, len(input))
	for i, value := range input {
		switch value := value.(type) {
		case map[interface{}]interface{}:
			output[i] = convertToMapStringInterface(value)
		case []interface{}:
			output[i] = convertSlice(value)
		default:
			output[i] = value
		}
	}
	return output
}
